-- Copyright (c) 2015,2016 Lucky Byte, Inc.
--
-- Summary : 业务处理主程序
--
-- Author  : 吴小虎 <xiaohu@lucky-byte.com>
-- Since   : 2016.4.29
--
-- History
--  * 2015.4.29 : 创建此文件
--  * 2015.5.05 : 记录交易流水
--  * 2015.8.20 : 初步支持插件
--

-- 检查交易环境, 由系统创建, 应该总是通过
if not reqt then
    logger.error('交易执行环境不完整，缺少[reqt] ...')
    return nil
end
for _, k in ipairs {'uuid', 'ichnl', 'packet'} do
    if not reqt[k] then
        logger.error('交易执行环境不完整，缺少[reqt.%s] ...', k)
        return nil
    end
end

-- 加载 plugins 目录中的插件，插件全部保存中 plugins 变量中(一个数组)
-- NOTE: 1.3 或以上版本启用
-- runtime.load_plugins()

-- 输出当前接入渠道相关信息
logger.info('交易渠道: [%s-%s]，模式[%s]...', reqt.ichnl.get('chnl'),
    reqt.ichnl.get('name'), reqt.ichnl.get('mode_name'))

-- 输出当前交易相关信息
logger.info('交易名称[%s], 内部交易[%s]，清算类[%s], ' ..
            '可冲正[%s], 可撤销[%s]，交易控制[%s], 控制代码[%s].',
    reqt.trinfo.name,
    reqt.trinfo.inner      and '是' or '否',
    reqt.trinfo.settl      and '是' or '否',
    reqt.trinfo.reversable and '是' or '否',
    reqt.trinfo.revokable  and '是' or '否',
    reqt.trinfo.trctl      and '是' or '否',
    reqt.trinfo.code)


-- 每笔终端请求交易首先记录流水信息
logger.trace('开始插入交易流水...')

reqt.trans_record = {
    uuid        = reqt.uuid,
    uuid_no     = 1,
    incoming    = true,
    chnl        = reqt.ichnl.get('chnl'),
    indirect    = reqt.ichnl.get('indirect'),
    trinfo      = core.json.encode(reqt.trinfo),
    netinfo     = reqt.netinfo,
    i_pkt       = reqt.packet.tojson()
}
if jdbc.upsert('pay_trlist', reqt.trans_record) < 0 then
    logger.error('记录交易[%s]的流水失败，请检查数据库...', reqt.uuid)
    return resp.respkt('01')
end


-- 补充请求交易流水(响应报文部分)
local _update_trans_record = function(respkt)
    -- 登记响应报文
    if respkt then
        reqt.trans_record.o_pkt = respkt.tojson()
        reqt.trans_record.status = 0
        local _code, _desc = resp.rescode(respkt)
        reqt.trans_record.notes = _code and _code .. '：' .. _desc or '无响应码'
    else
        reqt.trans_record.status = 1
        reqt.trans_record.notes = '未发送响应报文到客户端'
    end
    -- 登记交易商户信息(如果查询到的话，在未查询到商户时也会更新流水)
    if reqt.merch then
        reqt.trans_record.merch = reqt.merch.tojson()
    end
    -- 更新请求交易流水
    if jdbc.upsert('pay_trlist', reqt.trans_record, 'uuid', 'uuid_no') < 0 then
        logger.error('更新交易[%s][%s]的流水失败!',
            reqt.uuid, reqt.trans_record.get('uuid_no'))
        return false
    end
end


-- 生成响应报文，更新交易流水，返回生成的响应报文
local _resp_with_code = function(rescode)
    local _respkt = resp.respkt(rescode)
    _update_trans_record(_respkt)
    return _respkt
end


-- 查询交易的商户/终端信息，只有平台内登记过的商户终端才能进行交易
logger.trace('开始查询交易商户／终端信息...');

if not reqt.get_merch() then
    logger.error('平台内未查询到交易商户的信息，不能继续交易，请检查...');
    return _resp_with_code('02')
end
if not reqt.get_term() then
    logger.error('平台内未查询到交易终端信息，不能继续交易，请检查...');
    return _resp_with_code('03')
end

logger.debug('商户名称[%s]，商户编号[%s]，商户类型[%s].',
    reqt.merch.get('name'), reqt.merch.get('merno'),
    reqt.merch.get('inside') and '平台商户' or '外联商户')

-- 验证报文有效性
-- 各个渠道报文验证方式和内容可能不同，例如 POS 009.1 需验证报文 MAC
if not reqt.validate() then
    return _resp_with_code('12')
end

-- 检查交易控制中的配置的交易权限及交易限制
logger.trace('开始检查此交易能否满足商户配置的交易控制...')

if reqt.trinfo.trctl then   -- 如果没有设置交易控制标志，则不检查
    local _rescode = core.trctl.check({
        merch = reqt.merch, trinfo = reqt.trinfo, tramt = reqt.get_tramt()
    })
    if _rescode ~= '00' then
        logger.error('商户配置的交易控制不允许继续当前的交易...')
        return _resp_with_code(_rescode)
    end
    logger.debug('交易控制检测通过，继续此交易...')
else
    logger.info('交易[%s]未纳入交易控制管理，总是允许...', reqt.trinfo.name)
end


-- 平台内交易由平台处理，不需要转发
if reqt.trinfo.inner then
    logger.trace('此交易为平台内部交易，直接由平台处理，不执行转发...')
    _respkt = reqt.inner_proc()
    _update_trans_record(_respkt)
    return _respkt
end

-- 交易转发前处理
-- 如果返回错误，则不再继续交易
local _rescode = reqt.preproc()
if _rescode ~= '00' then
    return _resp_with_code(_rescode)
end

-- 转发请求到对应的接出渠道
logger.trace('当前交易需转发到第三方进行处理，开始转发...')
local _fowd = reqt.forward()
if not _fowd then
    _update_trans_record(nil)
    return nil
end

-- 转发结束后，需要更新请求交易流水中的响应报文部分
if _fowd.trans_record then
    reqt.dcflag = _fowd.trans_record.dcflag
    reqt.fee = _fowd.trans_record.fee
    reqt.trans_record.dcflag = reqt.dcflag
    reqt.trans_record.fee = reqt.fee
end
_update_trans_record(_fowd.respkt)

-- 转发交易未收到响应报文
if not _fowd.respkt then
    logger.error('转发交易报文已发送，但服务器未响应，不发送响应报文到客户端.')
    return nil
end
-- 交易失败，直接返回给客户端，无需后处理
if not resp.isok(_fowd.respkt) then
    logger.debug('响应报文中响应代码指示此交易失败，直接返回客户端.')
    return _fowd.respkt
end

-- 将转发结果保存起来，后处理中可以访问
resp.fowd = _fowd

-- 交易转发成功后处理
if reqt.postproc() ~= '00' then
    logger.warn('交易转发成功后处理失败，请检查...')
end
return _fowd.respkt
